OpenAI Assistants APIで生成したファイルをダウンロードする
2023年11月のアップデートで、OpenAI社はChatGPTを利用したAIアシスタントを構築できる Assistants APIを追加しました。
2023年12月現在はまだベータ版ですが、このAPIを利用すると、ChatGPT Web版で利用できた、Code Interpreterの機能をプログラム上で実行させることができます。 Web版のCode InterpreterではプログラムをChatGPT上で動かし、結果として生成されたファイルを受け取ることができました。当然このAPIを使っても、ファイルを生成させることができます。
ただ、では生成したファイルはどうやったらダウンロードできるのでしょう?
返ってくるメッセージの本文にダウンロードのパスが記載されるのではないの?と思われるかもしれません。しかし、私が試しにダミーデータを生成する指示を与えるプログラムを作成してみたところ、返ってきたメッセージの本文は次のようなものでした:
ダミーデータを10件生成し、CSV形式で出力しました。以下のリンクからダウンロードできます。
[ダウンロード dummy_data.csv](sandbox:/mnt/data/dummy_data.csv)
sandbox:/mnt/data/
って言われてもどこやねん、となってしまいますね。。
ということで自分が詰まったので、その対処法をメモとしてブログに残しておきます。
結論
- 結果として返ってくるメッセージデータに、生成したファイルのID(
file_id
)が含まれているので、これを取り出す files.content
メソッドでfile_id
を引数として指定することでファイルを取得する
これだけの話ではありますが、以下、実際のコードを交えて説明します。
まずはAssistants APIの基本的な処理のおさらい
Assistants APIの基本的な処理の流れは以下の通りです。 - アシスタントAIを作成 - アシスタントAIに指示するスレッドを作成 - 結果のデータを取得
以下、簡単なダミーデータを生成するコードのサンプルを示します。
import requests import time from openai import OpenAI # アシスタント作成処理 client = OpenAI() assistant = client.beta.assistants.create( name="My Assistant", instructions="あなたはデータ処理を行うAIアシスタントです。命令に従ってCSVを生成してください。", tools=[ {"type": "code_interpreter"}, ], model="gpt-4-1106-preview" ) # スレッド作成・実行 thread = client.beta.threads.create() message = client.beta.threads.messages.create( thread_id=thread.id, role="user", content="「品物」「単価」のフィールドを持つダミーデータを10件生成してください。品物の名前は日本語の果物名として、エントリ内でユニークとしてください。単価は日本円として、100円〜1000円の範囲で設定してください。結果はCSV形式で出力してください。" ) run = client.beta.threads.runs.create( thread_id=thread.id, assistant_id=assistant.id ) # 結果が生成される(Statusがcompletedになる)まで待つ while run.status != 'completed': run = client.beta.threads.runs.retrieve( thread_id=thread.id, run_id=run.id ) print(run.status) time.sleep(5) # 出力メッセージの取得 output_messages = client.beta.threads.messages.list( thread_id=thread.id ) print(output_messages.data) #debug用
client.beta.assistants.create()
でアシスタントを作成、続いてclient.beta.threads.create()
でスレッドを作成。スレッド内で指示するメッセージをclient.beta.threads.messages.create()
で定義して、client.beta.threads.runs.create()
で実行しています。
途中の while run.status != 'completed'
から始まる処理は、スレッドの実行ステータスを確認して、ChatGPTの処理が終わるまで待つ処理です。ステータスがcompleted
になると、出力結果が取り出せるようになります。ここでは出力結果をoutput_messages
に格納しています。
ファイル情報の取得
出力結果を格納したoutput_messages.data
内に含まれるデータは以下のような感じです。
[ThreadMessage(id='xxx', assistant_id='xxx', content=[MessageContentText(text=Text(annotations=[TextAnnotationFilePath(end_index=118, file_path=TextAnnotationFilePathFilePath(file_id='xxx'), start_index=79, text='sandbox:/mnt/data/dummy_fruits_data.csv', type='file_path')], value='ダミーデータを10件生成し、CSV形式で出力しました。以下のリンクからダウンロードできます。\n\n[ダウンロード dummy_data.csv](sandbox:/mnt/data/dummy_data.csv)'), type='text')], created_at=1703952985, file_ids=['file-xxx'], metadata={}, object='thread.message', role='assistant', run_id='run_xxx', thread_id='thread_xxx'), (以下省略)]
value
に含まれるのが回答の本文ですが、先ほども説明したようにこの回答に含まれるパスはダウンロードが可能なパスではありません。
実際に重要なのは、このデータ内に別に含まれているfile_ids
というフィールド内のIDとなります。このIDを指定してclient.files.content(file_id)
を実行することで、実際のファイルのデータを取得することができます。以下、上記を踏まえた先ほどのコードの続きです。output_messages.data
内では複数のファイルIDが含まれる可能性があるため、それらを抽出しfor
文で順次処理しています。
# 出力ディレクトリの指定 output_dir = "results" # 生成されたファイルのID情報をメッセージから抽出 file_ids = [ file_id for m in output_messages.data for file_id in m.file_ids ] print(file_ids) #debug用 # 取得したファイルIDをもとにローカルにファイルを書き込み for file_id in file_ids: output_path="{}/{}.csv".format(output_dir, file_id) write_file_data = client.files.content(file_id) file_data_bytes = write_file_data.read() with open(output_path, "wb") as file: file.write(file_data_bytes)
おわりに
というわけで、OpenAI assistant APIを利用したファイルのダウンロードの方法の紹介でした。説明したようにメッセージの本文にあるパス情報が有効ではない点にやや戸惑いますが、ベータ版ですので今後改善するかもしれません。このAPIでファイルを生成・ダウンロードする機能は非常に便利だと思いますので、試してみてはいかがでしょうか。ではでは。